package com.weareint.common.advices;

import com.weareint.common.advices.utils.MethodTypeUtil;
import com.weareint.common.dto.AbstractDTO;
import com.weareint.common.TokenProvider;
import com.weareint.common.entity.AbstractEntity;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.Objects;

/**
 * <pre>
 *      在Controller层调用Service层时，自动设置参数中的创建人，创建时间，修改人参数。
 *      如果参数是DTO，那么必须是 com.weareint.commons.dto.AbstractDTO 的子类。
 *      如果参数是Entity，那么必须是 com.weareint.commons.entity.AbstractEntity 的子类。
 * </pre>
 */
@Slf4j
@Aspect
@Component
public class AutoSetBasicPropertyAspect {

    @Autowired
    private TokenProvider tokenProvider;

    /**
     * <pre>
     *     开发包下的所有Controller
     * </pre>
     *
     */
    @Pointcut("within(@org.springframework.stereotype.Service *) " +
            "|| execution(* com.baomidou.mybatisplus.extension.service.IService.save*(..)) " +
            "|| execution(* com.baomidou.mybatisplus.extension.service.IService.update*(..)) ")
    public void serviceSaveOrUpdateMethodsPointcut() {

    }

    @Before("serviceSaveOrUpdateMethodsPointcut()")
    public void before(JoinPoint joinPoint) {
        MethodTypeUtil.TYPE type = MethodTypeUtil.toType(joinPoint.getSignature().getName());
        if (Objects.equals(type, MethodTypeUtil.TYPE.SAVE)
                || Objects.equals(type, MethodTypeUtil.TYPE.UPDATE)
                || Objects.equals(type, MethodTypeUtil.TYPE.SAVE_OR_UPDATE)){
            Object[] args = joinPoint.getArgs();
            if (null != args && args.length > 0){
                for (Object arg : args) {
                    // 所有的DTO都继承自 com.weareint.commons.dto.AbstractDTO
                    if (arg instanceof AbstractDTO){
                        fixDTO(arg);
                    }
                    // 所有的Entity都继承自 com.weareint.commons.entity.AbstractEntity
                    else if (arg instanceof AbstractEntity){
                        fixEntity(arg);
                    }
                    // 判断集合中是否有对象继承自 AbstractDTO 或 AbstractEntity
                    else if (arg instanceof Collection){
                        ((Collection)arg).forEach(elem -> {
                            if (AbstractDTO.class.isAssignableFrom(elem.getClass())){
                                this.fixDTO(elem);
                            }else if (AbstractEntity.class.isAssignableFrom(elem.getClass())){
                                this.fixEntity(elem);
                            }
                        });
                    }
                }
            }
        }
    }

    private void fixDTO(Object arg){
        AbstractDTO abstractDTO = (AbstractDTO) arg;
        if (abstractDTO.wasNewObject()){
            abstractDTO.setCreator(tokenProvider.getCurrentUserIdFromThreadLocal());
        }else {
            abstractDTO.setUpdater(tokenProvider.getCurrentUserIdFromThreadLocal());
        }
    }

    private void fixEntity(Object arg){
        AbstractEntity abstractEntity = (AbstractEntity) arg;
        if (abstractEntity.wasNewObject()){
            abstractEntity.setCreator(tokenProvider.getCurrentUserIdFromThreadLocal());
        }else {
            abstractEntity.setUpdater(tokenProvider.getCurrentUserIdFromThreadLocal());
        }
    }


}
